# Copyright (c) 2022-2025 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

add_custom_target(gc_ecma_common_tests)
add_dependencies(ecmascript_common_tests gc_ecma_common_tests)

set(COMMON_GC_MODULE_JS ${CMAKE_CURRENT_SOURCE_DIR}/common.js)
set(COMMON_GC_MODULE_BIN ${CMAKE_CURRENT_BINARY_DIR}/common.abc)
add_custom_target(gc_common_module
    COMMENT "running javascript common gc module compilation"
    COMMAND ${PANDA_RUN_PREFIX} $<TARGET_FILE:es2panda> --module ${COMMON_GC_MODULE_JS} --output ${COMMON_GC_MODULE_BIN}
)
add_dependencies(gc_common_module es2panda ark_asm ark)

function(panda_add_ecma_gc_test)
    set(prefix ARG)
    set(singleValues FILE)
    set(multiValues OPTIONS)
    cmake_parse_arguments(${prefix} "" "${singleValues}" "${multiValues}" ${ARGN})

    get_filename_component(TEST_NAME "${ARG_FILE}" NAME_WE)
    get_filename_component(TEST_FILE "${ARG_FILE}" REALPATH)
    set(BINARY_FILE "${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}.abc")

    compile_file_ecma(FILE ${TEST_FILE} OPTIONS "--module" OUTPUT_FILE ${BINARY_FILE} WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR})

    set(OPTIONS "--load-runtimes=ecmascript" "--compiler-enable-jit=false" "${ARG_OPTIONS}")

    add_custom_target(${TEST_NAME}
        COMMAND ${PANDA_RUN_PREFIX} $<TARGET_FILE:ark>
                              ${OPTIONS}
                              ${BINARY_FILE}
                              _GLOBAL::func_main_0
                      DEPENDS ${TEST_FILE}
                      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                      COMMENT "Running ${TEST_NAME} test"
                      DEPENDS ${BINARY_FILE})

    add_dependencies(${TEST_NAME} gc_common_module)
    add_dependencies(gc_ecma_common_tests ${TEST_NAME})
endfunction()

function(panda_add_ecma_gc_test_aot)
    set(prefix ARG)
    set(singleValues FILE)
    set(multiValues OPTIONS)
    cmake_parse_arguments(${prefix} "" "${singleValues}" "${multiValues}" ${ARGN})

    get_filename_component(TEST_NAME "${ARG_FILE}" NAME_WE)
    get_filename_component(TEST_FILE "${ARG_FILE}" REALPATH)
    set(BINARY_FILE "${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}.abc")

    compile_file_ecma(FILE ${TEST_FILE} OPTIONS "--module" OUTPUT_FILE ${BINARY_FILE} WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR})

    set(TEST_AN_FILE "${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}.an")
    set(AOT_OPTIONS "--load-runtimes=ecmascript" "${ARG_OPTIONS}" "--paoc-panda-files")
    add_custom_target("${TEST_NAME}.an"
        COMMAND ${PANDA_RUN_PREFIX} $<TARGET_FILE:ark_aot>
                              ${AOT_OPTIONS}
                              ${BINARY_FILE}
                              "--paoc-output"
                              ${TEST_AN_FILE}
                      DEPENDS ${TEST_FILE}
                      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                      COMMENT "Compiling ${TEST_NAME} test"
                      DEPENDS ${BINARY_FILE})

    set(OPTIONS "--load-runtimes=ecmascript" "--compiler-enable-jit=false" "${ARG_OPTIONS}")

    add_custom_target("${TEST_NAME}-aot"
        COMMAND ${PANDA_RUN_PREFIX} $<TARGET_FILE:ark>
                              ${OPTIONS}
                              "--aot-files"
                              ${TEST_AN_FILE}
                              ${BINARY_FILE}
                              _GLOBAL::func_main_0
                      DEPENDS ${TEST_FILE}
                      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                      COMMENT "Running ${TEST_NAME} test"
                      DEPENDS "${TEST_NAME}.an"
                      DEPENDS ${BINARY_FILE})

    add_dependencies("${TEST_NAME}-aot" gc_common_module)
    add_dependencies(gc_ecma_common_tests "${TEST_NAME}-aot")
endfunction()

function(panda_add_ecma_jsnapi_gc_test)
    set(prefix ARG)
    set(singleValues FILE)
    set(multiValues OPTIONS)
    cmake_parse_arguments(${prefix} "" "${singleValues}" "${multiValues}" ${ARGN})

    get_filename_component(TEST_NAME "${ARG_FILE}" NAME_WE)
    get_filename_component(TEST_FILE "${ARG_FILE}" REALPATH)
    set(BINARY_FILE "${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}.abc")

    compile_file_ecma(FILE ${TEST_FILE} OPTIONS "--module" OUTPUT_FILE ${BINARY_FILE} WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR})

    add_custom_target(source_js_file_${TEST_NAME}
                      DEPENDS ${BINARY_FILE})
    
    if (TARGET ecmascript_pending_exception_tests)
        add_dependencies(ecmascript_pending_exception_tests source_js_file_${TEST_NAME})
    else()
        panda_ecmascript_add_gtest(
            NO_CORES
            NAME ecmascript_pending_exception_tests
            SOURCES
                pending_exception_tests.cpp
            LIBRARIES
                arkruntime arkassembler
            SANITIZERS
                ${PANDA_SANITIZERS_LIST}
            DEPS_TARGETS
            source_js_file_${TEST_NAME}
        )
    endif()
endfunction()

# mm_tests target will launch tests that use GC the most
add_dependencies(mm_tests
                ecmascript_common_tests)

# Use --gc-trigger-type=debug-never to control GC in the test.
# In the test we don't need the runtime triggers GC during allocation.
panda_add_ecma_gc_test(FILE startGc.js OPTIONS "--gc-trigger-type=debug-never" "--g1-region-garbage-rate-threshold=0")
panda_add_ecma_gc_test(FILE scheduleGc.js OPTIONS "--gc-trigger-type=debug-never" "--gc-use-nth-alloc-trigger=true")
panda_add_ecma_gc_test(FILE spaceTypeTest.js OPTIONS "--gc-type=g1-gc" "--run-gc-in-place=true")
panda_add_ecma_gc_test(FILE concurrent.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never")
panda_add_ecma_gc_test(FILE hclass_changing_during_concurrent.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never" "--heap-verifier=fail_on_verification:post")
# NOTE(#29180): Flaky issue
#panda_add_ecma_gc_test(FILE pinObject.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never")
panda_add_ecma_gc_test(FILE copylexenvDynTest.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never" "--gc-use-nth-alloc-trigger=true" "--heap-verifier=fail_on_verification:pre:into:post")
panda_add_ecma_gc_test(FILE hclass_collected_before_object.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never" "--g1-track-freed-objects=true")
if (NOT PANDA_QEMU_BUILD)
    panda_add_ecma_gc_test(FILE registerNativeAllocation.js OPTIONS "--gc-trigger-type=debug-never")
endif()
# Flucky #14015
#panda_add_ecma_gc_test(FILE write_prebarrier_primitive_value.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never" "--g1-track-freed-objects=true")
# Running tests in AOT configuration
#panda_add_ecma_gc_test_aot(FILE write_prebarrier_primitive_value.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never" "--g1-track-freed-objects=true")
# Running tests via API calls
panda_add_ecma_jsnapi_gc_test(FILE moving_gc_when_pending_exception.js OPTIONS "--gc-type=g1-gc" "--gc-trigger-type=debug-never")
